package main

import (
	"bytes"
	"context"
	"embed"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/wailsapp/wails/v2/pkg/runtime"
	"github.com/xuri/excelize/v2"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	rt "runtime"
	"strings"
	"time"
)

// App struct
type App struct {
	ctx context.Context
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// 初始化事件监听
func (a *App) Init(ctx context.Context) {
	a.ctx = ctx
	runtime.EventsOn(a.ctx, "uploadFile", func(optionalData ...interface{}) {
		if len(optionalData) == 0 {
			log.Println("未接收到文件数据")
			return
		}

		// 将接收到的 Base64 字符串转换为 []byte
		base64String, ok := optionalData[0].(string)
		if !ok {
			log.Println("文件数据格式错误")
			return
		}

		fileData, err := base64.StdEncoding.DecodeString(base64String)
		if err != nil {
			log.Println("Base64 解码失败:", err)
			return
		}

		// 处理文件
		result := a.ProcessExcelFile(fileData)

		// 将结果发送回前端
		runtime.EventsEmit(a.ctx, "fileProcessed", result)
	})
}

// startup is called at application startup
func (a *App) startup(ctx context.Context) {
	// Perform your setup here
	a.ctx = ctx
	Setup()
	SetUpSSE()
	a.Init(ctx)
}

// domReady is called after front-end resources have been loaded
func (a App) domReady(ctx context.Context) {
	// Add your action here
}

// beforeClose is called when the application is about to quit,
// either by clicking the window close button or calling runtime.Quit.
// Returning true will cause the application to continue, false will continue shutdown as normal.
func (a *App) beforeClose(ctx context.Context) (prevent bool) {
	dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{
		Type:    runtime.QuestionDialog,
		Title:   "Quit?",
		Message: "Are you sure you want to quit?",
	})

	if err != nil {
		return false
	}
	return dialog != "Yes"
}

// shutdown is called at application termination
func (a *App) shutdown(ctx context.Context) {
	// Perform your teardown here
	fmt.Println("bye bye ...")
}

// Submit Form a submit formdata
func (a *App) Submit(file_type string, url string) (error, int64) {
	fmt.Println(file_type)
	fmt.Println(url)
	result := DB.Model(&Record{}).Create(&Record{
		FileType: file_type,
		Url:      url,
	})
	if result.Error != nil {
		return result.Error, 0
	}
	return nil, result.RowsAffected
}

// ProcessFile 处理前端上传的文件
func (a *App) ProcessExcelFile(fileData []byte) string {
	// 打开 Excel 文件
	file, err := excelize.OpenReader(bytes.NewReader(fileData))
	if err != nil {
		log.Println("打开 Excel 文件失败:", err)
		return "打开 Excel 文件失败"
	}
	defer file.Close()
	timestamp := time.Now().Unix()
	// 获取第一个工作表的名字
	sheetName := file.GetSheetName(0)

	// 读取工作表的所有行
	rows, err := file.GetRows(sheetName)
	if err != nil {
		log.Println("读取 Excel 文件失败:", err)
		return "读取 Excel 文件失败"
	}

	// 构建结果字符串
	result := ""
	for i, row := range rows {
		if i == 0 {
			continue
		}
		DB.Model(&Record{}).Create(&Record{
			Url:      row[1],
			FileType: checkFileType(row[1]),
			BatchNO:  fmt.Sprintf("BATCH-%d", timestamp),
		})
		result += fmt.Sprintf("第 %d 行: %v\n", i, row)
	}

	return result
}

// SaveFileDialog 打开文件保存对话框
func (a *App) SaveFileDialoging(dialogOptions runtime.SaveDialogOptions) (string, error) {
	// 调用 Wails 的 SaveFileDialog 方法
	return runtime.SaveFileDialog(a.ctx, dialogOptions)
}

// SaveFile 将文件数据保存到指定路径
func (a *App) SaveFile(filePath string, fileData []byte) error {
	// 将文件数据写入指定路径
	err := os.WriteFile(filePath, fileData, 0775)
	if err != nil {
		return err
	}
	return nil
}

type TemplateResponse struct {
	Data     []byte // 文件数据
	FileName string // 文件名
}

//go:embed template.xlsx
var templateFile embed.FS

// GetAppDataPath 返回应用数据目录路径
func GetAppDataPath(appName string) (string, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return "", fmt.Errorf("failed to get user home directory: %v", err)
	}

	// 根据操作系统选择应用数据目录
	var appDataPath string
	switch rt.GOOS {
	case "windows":
		appDataPath = filepath.Join(homeDir, "AppData", "Local", appName)
	case "darwin":
		appDataPath = filepath.Join(homeDir, "Library", "Application Support", appName)
	default:
		return "", fmt.Errorf("unsupported operating system: %s", rt.GOOS)
	}

	// 确保目录存在
	if err := os.MkdirAll(appDataPath, 0755); err != nil {
		return "", fmt.Errorf("failed to create app data directory: %v", err)
	}

	return appDataPath, nil
}

// InitTemplate 初始化模板文件
func InitTemplate() error {
	// 获取应用数据目录
	appDataPath, err := GetAppDataPath("wails-app")
	if err != nil {
		return fmt.Errorf("failed to get app data path: %v", err)
	}

	fmt.Println("App data path:", appDataPath)

	// 目标文件路径
	targetFilePath := filepath.Join(appDataPath, "template.xlsx")
	fmt.Println("Target file path:", targetFilePath)

	// 检查目标文件是否存在，如果不存在则从嵌入的文件系统中复制
	if _, err := os.Stat(targetFilePath); os.IsNotExist(err) {
		fmt.Println("Copying template file to target directory...")
		// 从嵌入的文件系统中读取模板文件
		fileData, err := templateFile.ReadFile("template.xlsx")
		if err != nil {
			return fmt.Errorf("failed to read embedded template file: %v", err)
		}

		// 将模板文件写入目标路径
		if err := os.WriteFile(targetFilePath, fileData, 0644); err != nil {
			return fmt.Errorf("failed to write template file to target directory: %v", err)
		}

		fmt.Println("Template file copied to:", targetFilePath)
	} else {
		fmt.Println("Template file already exists at:", targetFilePath)
	}

	return nil
}

// DownloadTemplate 读取模板文件并返回给前端
// DownloadTemplate 下载模板文件
func (a *App) DownloadTemplate() (TemplateResponse, error) {
	// 获取应用数据目录
	appDataPath, err := GetAppDataPath("wails-app")
	if err != nil {
		return TemplateResponse{}, fmt.Errorf("failed to get app data path: %v", err)
	}

	// 目标文件路径
	targetFilePath := filepath.Join(appDataPath, "template.xlsx")

	// 检查模板文件是否存在
	if _, err := os.Stat(targetFilePath); os.IsNotExist(err) {
		return TemplateResponse{}, fmt.Errorf("模板文件不存在: %v", err)
	}

	// 读取文件内容
	fileData, err := os.ReadFile(targetFilePath)
	if err != nil {
		return TemplateResponse{}, fmt.Errorf("读取模板文件失败: %v", err)
	}

	// 生成当前时间戳作为默认文件名
	timestamp := time.Now().Unix()
	defaultFileName := fmt.Sprintf("template_%d.xlsx", timestamp)

	// 返回文件数据和文件名
	return TemplateResponse{
		Data:     fileData,
		FileName: defaultFileName,
	}, nil
}

// LastTime 读取模板文件并返回给前端
func (a *App) LastTime() ([]Record, error) {
	records := []Record{}
	var latestBatchNO string
	DB.Model(&Record{}).Where("batch_no !=?", "").
		Order("created_at DESC").
		Limit(1).
		Pluck("batch_no", &latestBatchNO)
	DB.Model(Record{}).Where("batch_no=?", latestBatchNO).Find(&records)
	return records, nil
}

const HtmlPrefix, DocPrefix = "/home/html", "/home/html/diy/app/static/file"
const APIKEY = "sk-d34eb0b56d164153a9ab53f529a2a969"

func (a *App) GenCommand() (string, error) {
	execCode := ""
	willExecCmd := []string{}
	records := []Record{}
	var latestBatchNO string
	DB.Model(&Record{}).Where("batch_no !=?", "").
		Order("created_at DESC").
		Limit(1).
		Pluck("batch_no", &latestBatchNO)
	DB.Model(Record{}).Where("batch_no=?", latestBatchNO).Find(&records)
	prefix := "rm -rf" + "  "
	for _, re := range records {
		typeOf := checkFileType(re.Url)
		switch typeOf {
		case errorType:
			return "", errors.New("无效")
		case docType:
			text := strings.NewReplacer("\r\n", "", "\r", "", "\n", "").Replace(re.Url)
			regex := `^(http|https)://(www\.)?([a-zA-Z0-9.-]+(?:\.[a-zA-Z]{2,})+)(/.*)?$`
			re := regexp.MustCompile(regex)
			matches := re.FindStringSubmatch(text)
			if matches != nil && len(matches) >= 5 {
				newPath := fmt.Sprintf("%s", matches[4])
				willExecCmd = append(willExecCmd, HtmlPrefix+newPath)
			}
		case htmlType:
			willExecCmd = append(willExecCmd, DocPrefix+"/"+removeProtocol(re.Url))
		}
	}
	//最后讲prefix 与      willExecCmd进行连接
	tmpStr := ""
	for _, s := range willExecCmd {
		tmpStr += s + " "
	}
	execCode = prefix + tmpStr
	return execCode, nil
}

func (a *App) ValidRequst(batch_no string) ([]string, error) {
	records := []Record{}
	reqProcess := []string{}
	DB.Model(&Record{}).Where("batch_no=?", batch_no).Find(&records)
	flag := make(chan string)
	for _, re := range records {
		if checkFileType(re.Url) == errorType {
			continue
		}
		go func() {
			client := &http.Client{}
			req, _ := http.NewRequest("GET", re.Url, nil)
			resp, _ := client.Do(req)
			defer resp.Body.Close()

			if resp.StatusCode == 404 {
				flag <- "✅" + re.Url + ":" + fmt.Sprintf("%d\n", resp.StatusCode)
			} else {
				flag <- "❌" + re.Url + ":" + fmt.Sprintf("%d\n", resp.StatusCode)
			}
		}()
		select {
		case every := <-flag:
			reqProcess = append(reqProcess, every)
		}
	}
	return reqProcess, nil
}

func (a *App) ValidRecord(url string) string {
	client := &http.Client{}
	req, _ := http.NewRequest("GET", url, nil)
	resp, _ := client.Do(req)
	defer resp.Body.Close()
	if resp.StatusCode == 404 {
		return "✅" + url + "【" + fmt.Sprintf("已删除：%d\n", resp.StatusCode) + "】"
	} else {
		return "❌" + url + "【" + fmt.Sprintf("未删除：%d\n", resp.StatusCode) + "】"
	}
}

// 系统参数
func (a *App) SetSystemParam(config Config) {
	DB.Model(&Config{}).Where("id=?", 1).Updates(&config)
}

// 显示系统参数
func (a *App) ShowSystemParam() Config {
	cfg := Config{}
	DB.Model(&Config{}).First(&cfg)
	return cfg
}

// 历史record
func (a *App) RecordList() []Record {
	records := []Record{}
	DB.Model(&Record{}).Find(&records)
	return records
}

// 历史record
func (a *App) DeleteRecords(ids []uint) {
	DB.Model(&Record{}).Where("id in ?", ids).Delete(&Record{})
}

// 显示系统参数
func (a *App) ShowApiKey() AIConfig {
	cfg := AIConfig{}
	DB.Model(&AIConfig{}).First(&cfg)
	return cfg
}

// 设置参数
func (a *App) UpdateApiKey(config AIConfig) {
	DB.Model(&AIConfig{}).Where("id=?", 1).Updates(&config)
}

// chatto AI
func (a *App) ChatToAI(msg string) {
	chat := NewDeepseekClient()
	//chat.Chat(msg)
	chat.FreeChat(msg)
}
